#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include "mytbf.h"

//typedef void (*sighandler_t)(int);
static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER;
static struct mytbf_st* job[MYTBF_MAX];
static int inited = 0;
//static sighandler_t alrm_handler_save;

struct mytbf_st
{
	int cps;
	int burst;
	int token;
	int pos;
};

static void alrm_handler(int s)

static module_unload(void)
{
	pthread_mutex_destroy(&mut_job);
}

static module_load()

static int get_free_pos_unlocked(void)
{
	int i;
	for(i = 0; i < MYTBF_MAX; i++)
	{
		if(job[i] == NULL)
		{
			return i;
		}
	}

	return -1;
}

mytbf_t *mytbf_init(int cps, int burst)	
{
	struct mytbf_st *me;
	int pos;

	if(!inited)
	{
		module_load();
		inited = 1;
	}

	me = (mytbf_st)malloc(sizeof(*me));
	if(me == NULL)
	{
		return NULL;
	}

	me->token = 0;
	me->cps = cps;
	me->burst = burst;
	pthread_mutex_lock(&mut_job);
	pos = get_free_pos_unlocked();
	if(pos < 0)
	{
		pthread_mutex_unlock(&mut_job);
		free(me);
		return NULL;
	}

	me->pos = pos;

	job[pos] = me;
	pthread_mutex_unlock(&mut_job);

	return me;
}

static int min(int a, int b)
{
	if(a < b)
	{
		return a;
	}
	return b;
}

int mytbf_fetchtoken(mytbf_t *ptr, int size)
{
	struct mytbf_st *me = ptr;
	int n;

	if(size <= 0)
	{
		return -EINVAL;
	}

	while(me->token <= 0)
	{
		pause();
	}

	n = min(me->token, size);

	me->token -= n;
	return n;
}

int mytbf_returntoken(mytbf_t *ptr, int size)
{
	struct mytbf_st *me = ptr;
	if(size <= 0)
	{
		return -EINVAL;
	}

	me->token += size;

	if(me->token > me->burst)
	{
		me->token = me->burst;
	}

	return size;
}

int mytbf_destroy(mytbf_t *ptr)
{
	struct mytbf_st *me = ptr;

	pthread_mutex_lock(&mut_job);
	job[me->pos] = NULL;
	pthread_mutex_unlock(&mut_job);
	free(ptr);

	return 0;
}
